# 4.1 MCP 是什么？

**第4周 | 第1课 | Model Context Protocol 入门 | 预计时长：30分钟**

---

## 学习目标

完成本课后，你将能够：

- 解释 MCP 是什么以及它解决什么问题
- 用"USB 接口"类比说明 MCP 的核心价值
- 说出 MCP 架构的三个核心组件和三种核心操作
- 对比 MCP 与 Function Calling、Plugin 方案的差异

---

## 1. 从"手写集成"到"即插即用"

在前面的课程中，我们已经学会了用 Function Calling 让 Agent 调用工具。但有没有发现一个问题？

假设你有 3 个 Agent（客服 Agent、数据分析 Agent、运维 Agent），每个都需要访问数据库、调用天气 API、读取文件系统。没有统一标准时，你得为每个 Agent **手写一套集成代码**：

```
Agent A --[自定义代码]--> 数据库
Agent A --[自定义代码]--> 天气 API
Agent B --[自定义代码]--> 数据库
Agent B --[自定义代码]--> 天气 API
Agent C --[自定义代码]--> 数据库
Agent C --[自定义代码]--> 天气 API
```

**3 个 Agent x 3 个工具 = 9 条连接线**，每条都要单独编写、测试、维护。工具一升级，所有 Agent 都要改。

这就是 2024 年 11 月 Anthropic 提出 **MCP（Model Context Protocol）** 要解决的问题。

---

## 2. MCP 是什么？

> **MCP = AI Agent 的 USB 接口**

就像 USB 让键盘、鼠标、U 盘都能插到任何电脑上一样，MCP 让任何工具都能以标准方式接入任何 Agent。

```
              ┌─────────────────────────────┐
              │      MCP Server             │
              │  (工具提供者)                 │
              │                             │
              │  ┌─────┐  ┌─────┐  ┌─────┐  │
              │  │工具1 │  │工具2 │  │资源1 │  │
              │  └─────┘  └─────┘  └─────┘  │
              └──────┬──────────────────────┘
                     │ MCP 协议 (JSON-RPC)
                     │
              ┌──────┴──────────────────────┐
              │      MCP Client             │
              │  (Agent / LLM 应用)          │
              └─────────────────────────────┘
```

**核心思想**：工具提供者写一次 MCP Server，任何支持 MCP 的 Client（Claude Desktop、Cursor、你的自定义 Agent）都能直接使用，无需重写集成代码。

### 关键优势

| 对比维度 | 没有 MCP | 有 MCP |
|---------|---------|--------|
| 集成方式 | 每个 Agent 手写集成 | 一次编写，处处使用 |
| 工具升级 | 改所有 Agent | 只改 Server |
| 新增 Agent | 重写所有集成 | 配置即用 |
| 生态 | 封闭 | 开放，可共享 |

---

## 3. MCP 架构详解

MCP 架构由三个核心组件组成：

### 3.1 MCP Server（工具提供者）

一个轻量级程序，暴露工具和资源。它不直接跟 LLM 对话，而是通过标准协议提供服务。

```python
# 一个最简单的 MCP Server 示例
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("demo")

@mcp.tool()
def add(a: int, b: int) -> int:
    """返回两个数字的和"""
    return a + b

if __name__ == "__main__":
    mcp.run()
```

就这么简单。这个 Server 暴露了一个 `add` 工具，任何 MCP Client 都能调用。

### 3.2 MCP Client（工具使用者）

通常是 Agent 或 LLM 应用。它通过 MCP 协议连接到 Server，发现可用工具，然后调用它们。

```python
# Agent 侧：连接并调用工具
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def main():
    async with stdio_client(
        StdioServerParameters(command="python", args=["server.py"])
    ) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()

            # 列出可用工具
            tools = await session.list_tools()
            print(tools)  # [Tool(name='add', ...)]

            # 调用工具
            result = await session.call_tool("add", {"a": 3, "b": 5})
            print(result)  # 8
```

### 3.3 传输层（Transport）

MCP 支持两种传输方式：

- **stdio**（标准输入输出）：Server 作为子进程启动，通过 stdin/stdout 通信。适合本地工具。
- **HTTP+SSE**（Server-Sent Events）：Server 作为 HTTP 服务运行，Client 通过网络连接。适合远程服务。

```
本地工具 ────── stdio ────── Client（本地进程）
远程服务 ────── HTTP+SSE ── Client（网络请求）
```

---

## 4. MCP 的三种核心操作

MCP 协议定义了三种核心操作，覆盖了工具交互的完整生命周期：

### 4.1 tools/list — 发现可用工具

Client 问 Server："你有什么工具？"

```json
// 请求
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }

// 响应
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "calculator",
        "description": "执行数学运算",
        "inputSchema": {
          "type": "object",
          "properties": {
            "operation": { "type": "string", "enum": ["add", "subtract", "multiply"] },
            "a": { "type": "number" },
            "b": { "type": "number" }
          },
          "required": ["operation", "a", "b"]
        }
      }
    ]
  }
}
```

Agent 拿到工具列表后，就能知道有哪些工具可用、每个工具需要什么参数。这是 Agent 做工具选择的依据。

### 4.2 tools/call — 执行工具

Client 说："帮我调用这个工具。"

```json
// 请求
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "calculator",
    "arguments": { "operation": "add", "a": 10, "b": 20 }
  }
}

// 响应
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      { "type": "text", "text": "10 + 20 = 30" }
    ]
  }
}
```

### 4.3 resources/read — 读取资源

工具用于**执行操作**，资源用于**读取数据**。比如读取文件内容、数据库记录、配置信息等。

```python
@mcp.resource("config://app")
def get_config() -> str:
    """读取应用配置"""
    return """
    {
      "app_name": "demo",
      "version": "1.0.0",
      "debug": false
    }
    """
```

```json
// 请求
{ "jsonrpc": "2.0", "id": 3, "method": "resources/read",
  "params": { "uri": "config://app" } }

// 响应
{ "jsonrpc": "2.0", "id": 3,
  "result": { "contents": [{ "uri": "config://app", "text": "{...}" }] } }
```

**工具 vs 资源的区别**：
- 工具 = 动词（计算、搜索、发送）→ 有副作用
- 资源 = 名词（文件、配置、记录）→ 只读

---

## 5. MCP 与其他方案对比

### 5.1 MCP vs Function Calling

| | Function Calling | MCP |
|--|-----------------|-----|
| 标准化程度 | 各家 API 格式不同 | 统一 JSON-RPC 协议 |
| 耦合度 | 工具定义嵌入 Prompt | 工具独立于 Agent |
| 复用性 | 低（每个 Agent 要重新定义） | 高（一次编写多处使用） |
| 适用场景 | 单个 Agent 的轻量场景 | 多 Agent、多工具的复杂场景 |

```python
# Function Calling：工具定义与 Agent 代码耦合
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "parameters": { ... }
    }
}]
response = openai.chat.completions.create(
    model="gpt-4", tools=tools, messages=messages
)

# MCP：工具定义在 Server，Agent 只需连接
# Agent 不关心工具怎么实现的，连上就能用
async with ClientSession(read, write) as session:
    tools = await session.list_tools()  # 自动发现
```

### 5.2 MCP vs Plugin

| | Plugin（如 ChatGPT Plugins） | MCP |
|--|---------------------------|-----|
| 开放性 | 平台绑定 | 开源标准 |
| 传输 | 仅 HTTP | stdio + HTTP+SSE |
| 资源支持 | 无 | 支持 resources |
| 社区 | 封闭生态 | 开放生态 |

### 5.3 什么时候用哪个？

- **只有 1 个 Agent + 少量工具** → Function Calling 足够
- **多个 Agent 共享工具 / 工具需要独立部署** → MCP
- **Agent 需要读取大量结构化数据** → MCP 的 resources 更适合
- **想复用别人的工具** → MCP 生态

---

## 6. MCP 生态现状

截至 2025 年，MCP 已经成为事实上的 AI 工具接入标准：

- **Claude Desktop** 原生支持 MCP 配置
- **Cursor** 通过 MCP 接入自定义工具
- **开源社区** 已有数百个 MCP Server（GitHub、Slack、数据库、文件系统等）
- **主流语言** 都有 SDK：Python、TypeScript、Java、Go、Rust

你可以在 [github.com/modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers) 找到官方维护的 Server 集合。

---

## 动手练习

### 练习 1：理解 MCP 架构

回答以下问题：

1. 你的项目中有一个数据库查询工具，3 个不同的 Agent 都需要使用。用 MCP 和不用 MCP 分别需要写多少份集成代码？
2. `tools/list`、`tools/call`、`resources/read` 分别在什么场景下使用？
3. 什么情况下选择 stdio 传输？什么情况下选择 HTTP+SSE？

### 练习 2：阅读 MCP Server 代码

阅读下面的代码，标注出每个部分的作用：

```python
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("weather-service")

@mcp.tool()
def get_weather(city: str) -> str:
    """获取指定城市的天气信息"""
    # TODO: 实现天气查询逻辑
    return f"{city} 的天气：晴，25°C"

@mcp.resource("cities://list")
def list_cities() -> str:
    """列出支持的城市"""
    return "北京,上海,广州,深圳"

@mcp.resource("weather://{city}/current")
def get_current_weather(city: str) -> str:
    """获取指定城市的实时天气"""
    return get_weather(city)

if __name__ == "__main__":
    mcp.run()
```

问题：
- 这个 Server 暴露了几个工具？几个资源？
- Agent 调用 `get_weather("北京")` 会经过哪些步骤？
- `resources/read` 能读取哪些 URI？

### 练习 3：配置 Claude Desktop 使用 MCP

在你的 Claude Desktop 配置文件中添加一个 MCP Server（以官方 GitHub Server 为例）：

```json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "your_token_here"
      }
    }
  }
}
```

配置文件位置：
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

配置后重启 Claude Desktop，你就能在对话中使用 GitHub 相关的工具了。

---

## 本课总结

- **MCP 是 AI Agent 的 USB 接口**：标准化了工具接入方式，实现"一次编写，处处使用"
- **三大组件**：MCP Server（提供工具）、MCP Client（使用工具）、Transport（传输层）
- **三种核心操作**：
  - `tools/list` — 发现可用工具
  - `tools/call` — 执行工具调用
  - `resources/read` — 读取资源数据
- **与 Function Calling 的关系**：不是替代，而是补充。MCP 解决的是工具复用和生态问题
- **生态正在快速增长**：主流平台和语言均已支持

---

## 下一课预告

下一课我们将动手搭建第一个 MCP Server，用 Python 实现计算器、天气查询、时间查询等工具，并让 Agent 通过 MCP 协议调用它们。准备好你的 Python 环境！
